/***********************************************************************************************//**
 * \file   event_control.c
 * \brief  SW Timer
 ***************************************************************************************************
 * <b> (C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
 ***************************************************************************************************
 * This file is licensed under the Silabs License Agreement. See the file
 * "Silabs_License_Agreement.txt" for details. Before using this software for
 * any purpose, you must agree to the terms of that agreement.
 **************************************************************************************************/


/* standard library headers */
#include <stddef.h>
#ifdef HOST
#include <stdint.h>
#endif /* HOST */

/* timer headers */
#ifdef HOST
#include "system_timer.h"
#else /* !HOST */
#include "em_rtcc.h"
#endif /* HOST */

/* Own header*/
#include "event_control.h"

/***********************************************************************************************//**
 * @addtogroup Platform
 * @{
 **************************************************************************************************/

/***********************************************************************************************//**
 * @addtogroup evt_ctrl
 * @{
 **************************************************************************************************/

/***************************************************************************************************
 Local Macros and Definitions
 **************************************************************************************************/

/** Timer Frequency used. */
#define TIMER_CLK_FREQ ((uint32_t)4096)
/** Convert msec to timer ticks. */
#define TIMER_MS_2_TIMERTICK(ms) ((TIMER_CLK_FREQ * (ms)) / 1000)

/***************************************************************************************************
 Static Function Declarations
 **************************************************************************************************/

static inline uint32_t getTime(void);
static inline uint32_t getTimeToExecuteMs(uint16_t delay);
static inline uint32_t getTimeToExecuteQs(uint16_t delay);
static inline uint32_t getTimeToExecuteMinutes(uint16_t delay);

/***************************************************************************************************
 Public Function Definitions
 **************************************************************************************************/

void eventControlSetDelayMS(EmberEventControl* event, uint16_t delay)
{
  event->timeToExecute = getTimeToExecuteMs(delay);
  event->status = EVENT_MS_TIME;
}

void eventControlSetDelayQS(EmberEventControl* event, uint16_t delay)
{
  event->timeToExecute = getTimeToExecuteQs(delay);
  event->status = EVENT_MS_TIME;
}

void eventControlSetDelayMinutes(EmberEventControl* event, uint16_t delay)
{
  event->timeToExecute = getTimeToExecuteMinutes(delay);
  event->status = EVENT_MS_TIME;
}

uint32_t msToNextEventExtended(EmberEventData *events, uint32_t maxMs, uint8_t* returnIndex)
{
  EmberEventData *nextEvent;
  uint32_t nowMS32 = getTime();
  uint8_t index = 0;
  if (returnIndex != NULL) {
    *returnIndex = 0xFF;
  }

  for (nextEvent = events; ; nextEvent++) {
    EmberEventControl *control = nextEvent->control;
    if (control == NULL)
      break;

    if (control->status != EVENT_INACTIVE) {
      if (control->status == EVENT_ZERO_DELAY
          || timeGTorEqualInt32u(nowMS32, control->timeToExecute)) {
        if (returnIndex != NULL) {
          *returnIndex = index;
        }
        return 0;
      } else {
        uint32_t duration = elapsedTimeInt32u(nowMS32, control->timeToExecute);
        if (duration < maxMs) {
          maxMs = duration;
          if (returnIndex != NULL) {
            *returnIndex = index;
          }
        }
      }
    }
    index++;
  }
  return maxMs;
}

uint32_t msToNextEvent(EmberEventData *events, uint32_t maxMs)
{
  return msToNextEventExtended(events, maxMs, NULL);
}

void runEvents(void)
{
  uint8_t i, j;
  EmberEventData* tmpEvts = stackEvts;

  for (i = 0; i < 2; i++) {
    j = 0;
    while (tmpEvts[j].control != NULL) {
      if (tmpEvts[j].control->status != EVENT_INACTIVE) {
        if ((tmpEvts[j].control->status == EVENT_ZERO_DELAY) ||
            (timeGTorEqualInt32u(getTime(), tmpEvts[j].control->timeToExecute))) {
          ((void (*)(void))(tmpEvts[j].handler))();
        }
      }
      j++;
    }
    tmpEvts = emAppEvents;
  }
}


/***************************************************************************************************
 Static Function Definitions
 **************************************************************************************************/

static inline uint32_t getTime(void)
{
#ifdef HOST
  return sysTmrGetMillisecondTick();
#else /* !HOST */
  return RTCC_CounterGet();
#endif /* HOST */
}

static inline uint32_t getTimeToExecuteMs(uint16_t delay)
{
#ifdef HOST
  return sysTmrGetMillisecondTick() + (delay);
#else /* !HOST */
  return RTCC_CounterGet() + (uint32_t)TIMER_MS_2_TIMERTICK(delay);
#endif /* HOST */
}

static inline uint32_t getTimeToExecuteQs(uint16_t delay)
{
#ifdef HOST
  return sysTmrGetMillisecondTick() + (((uint32_t)delay) << 8);
#else /* !HOST */
  return RTCC_CounterGet() + (((uint32_t)TIMER_MS_2_TIMERTICK(delay)) << 8);
#endif /* HOST */
}

static inline uint32_t getTimeToExecuteMinutes(uint16_t delay)
{
#ifdef HOST
  return sysTmrGetMillisecondTick() + (((uint32_t)delay) << 16);
#else /* !HOST */
  return RTCC_CounterGet() + (((uint32_t)TIMER_MS_2_TIMERTICK(delay)) << 16);
#endif /* HOST */
}


/** @} (end addtogroup evt_ctrl) */
/** @} (end addtogroup Platform) */

